package moTSP;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import nsga.Individual;

import common.GeneticOperations;

public class TspGeneticOperations implements GeneticOperations<TspGenotype> {
    
    private TownsMap townsMap;
    private double param_p;
    
    /**
     * 
     * @param aTownsMap
     * @param p paramter dla operatora inver-over
     */
    public TspGeneticOperations(TownsMap aTownsMap, double aParam_p) {
        this.townsMap = aTownsMap;
        this.param_p = aParam_p;
    }

    @Override
    public List<Individual<TspGenotype>> createAllResults() {
        return null;
    }

    @Override
    public TspGenotype createGenotypeFromString(String genotype) {
        return null;
    }

    @Override
    public TspGenotype createRandomGenotype() {
                
        TspGenotype result = new TspGenotype(townsMap.getNumOfTowns());
        return result;
        
    }

    /**
     * Inver-over operator
     */
    @Override
    public List<TspGenotype> crossover(TspGenotype g1, TspGenotype g2) {
        
        Random rand = new Random();
        
        TspGenotype result = new TspGenotype(g1);
        List<TspGenotype> resultList = new ArrayList<TspGenotype>(1);
        resultList.add(result);
        
        List<Integer> resultVO = result.getVisitingOrder();
        
        int firstCity = result.getRandomCityNum();
        int secondCity;
        if (rand.nextDouble() < param_p || g2.cityIsLast(firstCity)) {
            // nie patrzy na g2
            secondCity =  result.getRandomCityNumOtherThan(firstCity);
        }
        else {
            // patrzy na g2
            secondCity = g2.getNextCity(firstCity);
        }
        if (    (resultVO.indexOf(secondCity) == 1 + resultVO.indexOf(firstCity))
             || (resultVO.indexOf(secondCity) == -1 + resultVO.indexOf(firstCity)) ) {
            // brak inwersji
        }
        else {
            // inwersja
            result.inverse(firstCity,secondCity);
        }
        
        return resultList;
    }

    @Override
    public List<Double> getFitnessesFromValue(List<Double> values) {
        return values;
    }

    @Override
    public List<Double> getValues(TspGenotype genotype) {
        
        double[] result = new double[townsMap.getNumOfObjectives()];
        
        List<Integer> visitingOrder = genotype.getVisitingOrder();
        for (int i = 0; i < visitingOrder.size() - 1 ; i++) {
            
            int from = visitingOrder.get(i);
            int to = visitingOrder.get(i + 1);
            
            for (int objNum = 0; objNum < townsMap.getNumOfObjectives(); objNum++) {
                result[objNum] += townsMap.getTravelCost(from, to, objNum);
            }
            
        }
        List<Double> resultList = new ArrayList<Double>(townsMap.getNumOfObjectives());
        for (double r : result) {
            resultList.add(r);
        }
        return resultList;
    }

    @Override
    public void mutate(TspGenotype genotype) {
        // nie ma operacji mutacji
    }

    @Override
    public TspGenotype duplicateGenotype(TspGenotype genotype) {
        return new TspGenotype(genotype);
        
    }

}
